package itsm.isperp.framework.web.request;

import itsm.isperp.framework.cache.Cache;
import itsm.isperp.framework.cache.CacheManager;
import itsm.isperp.framework.collection.tree.ITreeNode;
import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.data.mybatis.domain.AbstractTreeNode;
import itsm.isperp.framework.utils.Pair;
import itsm.isperp.framework.web.domain.CountQuery;
import itsm.isperp.module.dto.project.ProjectDomain;
import itsm.isperp.module.utils.ProjectDomainUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.jdbc.core.JdbcTemplate;

/**
 * 
 * 默认统计查询器的实现
 * 
 * @author lizx
 * @date 2013-8-13
 * 
 */
public class DefaultCountQuery implements CountQuery {

	static final String QUERY_COUNT = " SELECT COUNT(*) AS CT FROM %s a WHERE 1=1 ";
	static final String QUERY_COUNT_REQ = " SELECT COUNT(*) AS CT %s    ";

	static final String UNION_ALL = " UNION ALL ";

	String from;

	ProjectDomain projectDomain;

	Map<String, Pair<Boolean, String>> filter;

	private JqGridFilter queryFilter;

	private boolean fromRequest;

	public DefaultCountQuery() {
		filter = new LinkedHashMap<>();
	}

	public DefaultCountQuery(String from) {
		this.from = from;
		filter = new LinkedHashMap<>();
	}

	public String getFrom() {
		return from;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public boolean isFromRequest() {
		return fromRequest;
	}

	public void setFromRequest(boolean fromRequest) {
		this.fromRequest = fromRequest;
	}

	@Override
	public String generatorCountQuerySql() {
		StringBuilder sb = new StringBuilder();
		String query = String.format((fromRequest ? QUERY_COUNT_REQ
				: QUERY_COUNT), this.from);

		if (queryFilter != null) {

			query = query + queryFilter.getSql();
		}
		sb.append(query);
		if (filter != null && filter.size() > 0) {
			Iterator<Pair<Boolean, String>> iter = this.filter.values()
					.iterator();

			

			if (projectDomain == null) {
				sb.append(" AND ").append(iter.next().getRightObject());
			} else {
				sb.append(ProjectDomainUtils
						.getUserDomainSql(this.projectDomain));
				sb.append(" AND ").append(iter.next().getRightObject());
			}

			while (iter.hasNext()) {
				sb.append(UNION_ALL).append(query);
				if (projectDomain == null) {
					sb.append(" AND ").append(iter.next().getRightObject());
				} else {
					sb.append(ProjectDomainUtils
							.getUserDomainSql(this.projectDomain));
					sb.append(" AND ").append(iter.next().getRightObject());
				}
			}
		}
		return sb.toString();
	}

	public String generatorCountNodeQuerySql(String nodeName) {
		StringBuilder sb = new StringBuilder();
		if (filter != null) {
			sb.append(
					String.format(
							(fromRequest ? QUERY_COUNT_REQ : QUERY_COUNT),
							this.from)).append(" AND ")
					.append(filter.get(nodeName).getRightObject());
		}
		return sb.toString();
	}

	@Override
	public CountQuery from(String sql) {
		this.from = sql;
		return this;
	}

	@Override
	public CountQuery addCountFilter(String key, String filterSql) {
		this.addCountFilter(key, false, filterSql);
		return this;
	}

	@Override
	public CountQuery addCountFilter(String key, boolean main, String filterSql) {
		Pair<Boolean, String> p = new Pair<>(main, filterSql);
		this.filter.put(key, p);
		return this;
	}

	@Override
	public Long getTreeNodeCount(String nodeName) {

		JdbcTemplate jdbcTemplate = ContextHolder
				.getSpringBean(JdbcTemplate.class);
		return jdbcTemplate.queryForObject(
				this.generatorCountNodeQuerySql(nodeName), Long.class);

	}

	public List<Long> getCountResult() {
		String sql = this.generatorCountQuerySql();
		JdbcTemplate jdbcTemplate = ContextHolder
				.getSpringBean(JdbcTemplate.class);
		return jdbcTemplate.queryForList(sql, Long.class);

	}

	@Override
	public ITreeNode[] getTreeNodes() {

		Set<String> keys = this.filter.keySet();

		String ot = ContextHolder.getConfigByKey("queryCacheOuttime");
		int otInt = 0;
		try {
			otInt = Integer.parseInt(ot);
		} catch (Exception e) {
			otInt = 5000;
		}

		ITreeNode[] nodes = null;
		Cache c = null;
		String cKey = null;
		if (otInt > 0) {
			cKey = ContextHolder.getLoginUsername() + "_" + this.from + "_"
					+ keys.size();
			c = CacheManager.getCacheInfo(cKey);
		}

		if (c == null) {

			JdbcTemplate jdbcTemplate = ContextHolder
					.getSpringBean(JdbcTemplate.class);
			nodes = new ITreeNode[keys.size()];
			List<Long> result = jdbcTemplate.queryForList(
					this.generatorCountQuerySql(), Long.class);

			Iterator<String> iter = keys.iterator();
			for (int i = 0; i < keys.size(); i++) {
				String key = iter.next();
				ITreeNode tn = new AbstractTreeNode();

				tn.setId("c_" + key.hashCode());
				Pair<Boolean, String> p = this.filter.get(key);
				if (p.getLeftObject()) {
					tn.setName(key + "(<label class='c-main'>" + result.get(i)
							+ "</label>)");
				} else {
					tn.setName(key + "(" + result.get(i) + ")");
				}
				tn.setLeaf(true);
				tn.setTreenodePath(key);
				nodes[i] = tn;
			}
			if (otInt > 0) {
				CacheManager.putCacheInfo(cKey, nodes, otInt);
			}
		} else {
			return (ITreeNode[]) c.getValue();
		}

		return nodes;
	}

	@Override
	public ITreeNode[] getTreeNodes(String rootName) {
		Set<String> keys = this.filter.keySet();
		JdbcTemplate jdbcTemplate = ContextHolder
				.getSpringBean(JdbcTemplate.class);
		ITreeNode[] root = new ITreeNode[1];

		List<Object> result = jdbcTemplate.queryForList(
				this.generatorCountQuerySql(), Object.class);
		List<ITreeNode> nodes = new ArrayList<>();
		Iterator<String> iter = keys.iterator();
		for (int i = 0; i < keys.size(); i++) {
			String key = iter.next();
			ITreeNode tn = new AbstractTreeNode();
			Pair<Boolean, String> p = this.filter.get(key);

			if (p.getLeftObject()) {
				tn.setName(key + "(<label class='c-main' style='color:red'>"
						+ result.get(i) + "</label>)");
			} else {
				tn.setName(key + "(" + result.get(i) + ")");
				tn.setLeaf(true);
			}

			tn.setId(key);
			tn.setTreenodePath(key);
			nodes.add(tn);
		}
		root[0] = new AbstractTreeNode();
		root[0].setName(rootName);
		root[0].setOpen(true);
		root[0].setChildren(nodes);
		return root;
	}

	@Override
	public String getFilter(String key) {
		Pair<Boolean, String> p = this.filter.get(key);
		if (p == null) {
			return null;
		}
		return p.getRightObject();
	}

	public String getFilter() {
		String filter = "( (1=0)  ";

		for (Pair<Boolean, String> s : this.filter.values()) {
			filter += " OR (" + s.getRightObject() + ") ";

		}
		return filter + " ) ";
	}

	@Override
	public int getType() {
		return 0;
	}

	@Override
	public void setProjectDomain(ProjectDomain projectDomain) {
		this.projectDomain = projectDomain;
	}

	@Override
	public void addQueryFilterRule(String field, JqGridFilterRuleOp op,
			String data) {
		if (this.queryFilter == null) {
			queryFilter = new JqGridFilter();
			queryFilter.setGroupOp("AND");
			queryFilter.setRules(new ArrayList<JqGridFilterRule>());
		}
		queryFilter.addRule(new JqGridFilterRule(field, op, data));
	}

	@Override
	public String getFisrtQueryKey() {

		for (String key : filter.keySet()) {
			return key;
		}
		return null;
	}

}
